package com.lsy.poi.row;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.log4j.Logger;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;

import com.lsy.poi.Parser;
import com.lsy.poi.Student;
import com.lsy.poi.bean.FixedRangeIndexer;
import com.lsy.poi.bean.Index;
import com.lsy.poi.bean.Indexer;
import com.lsy.poi.cell.CellParser;
import com.lsy.poi.cell.extractor.CellExtractor;
import com.lsy.poi.cell.indexer.CellIndexer;
import com.lsy.poi.cell.validator.CellValidator;
import com.lsy.poi.cell.validator.EquivalenceValidator;
import com.lsy.poi.exception.row.IndexOverlappingException;
import com.lsy.poi.row.indexer.FixedRangeRowIndexer;
import com.lsy.poi.row.indexer.RowIndexer;
import com.lsy.poi.row.validator.RowValidator;
import com.lsy.poi.sheet.SheetParser;
import com.swa99ylum.pxp.a.a005.Cell;

public class RowParser extends Parser {
	
	private static Logger logger = Logger.getLogger(RowParser.class);
	
	private int beginIndex;
	private int endIndex;
	
	private RowIndexer rowIndexer;
	
	/**
	 * row 和 cellParsers、validators 之间是 "多对一" 的 关系，
	 * 即 "多行row" 可以使用 "一组CellParser、一组RowValidator" 进行解析、验证
	 */
	private XSSFRow[]		rows;
	private CellParser[]	cellParsers;
	private RowValidator[]	validators;
	
	private List<?> hookList;  //TODO: 如果是 List<String> 貌似 没法做了。。。
//	private String[] propertyNames;
//	private Class<?> clazz;  //TODO: 如果是 List<String> 貌似 没法做了。。。
	
	private RowMapper<?> rowMapper;
	
	/** 默认的 验证器列表：空，即 不做任何验证  */
	private final static RowValidator[] DEFAULT_VALIDATORS = new RowValidator[]{};
	
	@Override
	public void spreadErrorHook(List<String> errors) {
		for (CellParser cellParser : cellParsers) {
			cellParser.spreadErrorHook(errors);
		}
		
		for (RowValidator rowValidator : validators) {
			rowValidator.setErrors(errors);
		}
	}
	
	/**
	 * 构造器
	 * @param <T>
	 */
	public <T> RowParser(List<T> hookList, RowMapper<T> rowMapper) {
		
	}
	
	//===================
	public RowParser(int beginIndex, int endIndex, CellParser[] cellParsers, RowValidator[] validators) {
		this(beginIndex, endIndex, cellParsers, validators, null, null);
	}
	public RowParser(int index, CellParser[] cellParsers, RowValidator[] validators) {
		this(index, index, cellParsers, validators);
	}
	
	
	public RowParser(int beginIndex, int endIndex, CellParser[] cellParsers) {
		this(beginIndex, endIndex, cellParsers, DEFAULT_VALIDATORS);
	}
	public RowParser(int index, CellParser[] cellParsers) {
		this(index, index, cellParsers);
	}
	
	//===================
	public <T> RowParser(int beginIndex, int endIndex, CellParser[] cellParsers, RowValidator[] validators, List<T> hookList) {
		this(beginIndex, endIndex, cellParsers, validators, hookList, new RowMapper<T>(0));
	}
	public <T> RowParser(int index, CellParser[] cellParsers, RowValidator[] validators, List<T> hookList) {
		this(index, index, cellParsers, validators, hookList);
	}

	
	public <T> RowParser(int beginIndex, int endIndex, CellParser[] cellParsers, List<T> hookList) {
		this(beginIndex, endIndex, cellParsers, DEFAULT_VALIDATORS, hookList);
	}
	public <T> RowParser(int index, CellParser[] cellParsers, List<T> hookList) {
		this(index, index, cellParsers, hookList);
	}
	
	//===================
	
	//TODO:123123123
	public <T> RowParser(RowIndexer rowIndexer, CellParser[] cellParsers, RowValidator[] validators, List<T> hookList, RowMapper<T> rowMapper) {
		super();
		this.beginIndex = -1;
		this.endIndex = -1;
		this.rowIndexer = rowIndexer;
		
		this.cellParsers = cellParsers;
		this.validators = validators;
		
		this.hookList = hookList;
		this.rowMapper = rowMapper;
	}
	
	//TODO:456456456
	public <T> RowParser(RowIndexer rowIndexer, CellParser[] cellParsers, List<T> hookList, RowMapper<T> rowMapper) {
		this(rowIndexer, cellParsers, DEFAULT_VALIDATORS, hookList, rowMapper);
	}
	
	
	
	public <T> RowParser(int beginIndex, int endIndex, CellParser[] cellParsers, RowValidator[] validators, List<T> hookList, RowMapper<T> rowMapper) {
		super();
		this.beginIndex = beginIndex;
		this.endIndex = endIndex;
		this.rowIndexer = new FixedRangeRowIndexer(beginIndex, endIndex);
		
		
		this.cellParsers = cellParsers;
		this.validators = validators;
		
		
		this.hookList = hookList;
//		this.propertyNames = propertyNames;
//		this.clazz = clazz;
		this.rowMapper = rowMapper;
		
//		if(propertyNames!=null && hookList!=null && clazz!=null) {
//			for (int i=beginIndex; i<endIndex+1; i++) {
//				T ele;
//				try {
//					ele = clazz.newInstance();
//					hookList.add(ele);
//				} catch (InstantiationException | IllegalAccessException e) {
//					e.printStackTrace();
//				}
//			}
//			this.hookList = hookList;
//			this.clazz = clazz;
//			
//			this.propertyNames = propertyNames;
//		}
	}
	public <T> RowParser(int index, CellParser[] cellParsers, RowValidator[] validators, List<T> hookList, RowMapper<T> rowMapper) {
		this(index, index, cellParsers, validators, hookList, rowMapper);
	}

	
	public <T> RowParser(int beginIndex, int endIndex, CellParser[] cellParsers, List<T> hookList, RowMapper<T> rowMapper) {
		this(beginIndex, endIndex, cellParsers, DEFAULT_VALIDATORS, hookList, rowMapper);
	}
	public <T> RowParser(int index, CellParser[] cellParsers, List<T> hookList, RowMapper<T> rowMapper) {
		this(index, index, cellParsers, hookList, rowMapper);
	}
	
	
	


	/**
	 * 核心方法
	 * @param <T>
	 */
	public void parse() throws Exception {
//		@SuppressWarnings("unchecked")
//		List<?> eleList = hookList;
//		T ele = clazz.newInstance();
//		eleList.add(ele);
//		Object ele;
		
		for (int rowIndex = 0; rowIndex<rows.length; rowIndex++) {
			XSSFRow row = rows[rowIndex];
			logger.debug("********************************" + row.getRowNum());
			
			printRow(row);
			
			Set<Integer> cellIndexSet = new HashSet<Integer>();//用于检测 "同一 row 的 多个 cell 不应当出现 index 之间的 重叠"
			
			
//			for (CellParser cellParser : cellParsers) {
//				//1、构建 XSSFCell[] cells
//				int beginIndex = cellParser.getBeginIndex();
//				int endIndex = cellParser.getEndIndex();
//				
//				XSSFCell[] cells = new XSSFCell[endIndex-beginIndex+1];
//				
//				for(int i=beginIndex; i<endIndex+1; i++) {
//					int index = i-beginIndex;
//					cells[index] = row.getCell(i); //row.getCell(i) 的结果 可能为 null
//					
//					if(!cellIndexSet.add(i)) {
//						/*
//						 * 1) 同一 row   的 多个 cell，不应当出现 cellIndex 之间的 重叠
//						 * 	对于一个 row 来说，有 2 个 CellParser 中 都同时包含了 (1行,3列) 这个单元格 的 cellValue，这其实是没有任何意义的
//						 * 
//						 * 2) 同一 sheet 的 多个  row，	可以出现  rowIndex 之间的 重叠
//						 * 	1. 第一次 可以 解析 1-6 行（row）的 0-10 列；第二次 可以解析 1-6 行（row）的 11-20 列
//						 * 	2. 可以对 1-6 行（row）的 0-10 列 进行反复的 解析
//						 * 
//						 */
//						String msg = row.getSheet().getSheetName() + "页，"
//									+ row.getRowNum() + "行"
//									+ i + "列 的 单元格 被 重复提取了";
//						
//						throw new IndexOverlappingException(msg);
//					}
//				}
//				
//				//2、将 cells 交给  cellParser
//				cellParser.setCells(cells);
//				
//				//3、解析 cellParser 中的  XSSFCell[] cells（提取值）
//				cellParser.parse();
//				
//			}
			
			for (CellParser cellParser : cellParsers) {
				logger.debug("==================================@@@@");
				boolean started = false;
				
				List<XSSFCell> cellList = new ArrayList<>(); 
				
				CellIndexer cellIndexer = cellParser.getCellIndexer();
				
				while(true) {
					int i = cellIndexer.getIndex();
					
					/** 避免 无限循环的 保护熔断 	 */
					if(i< row.getFirstCellNum()) continue;
					if(i>= row.getLastCellNum()) break; //getLastCellNum() 是最后一个 "有值行" 的 列号+1（从 0 开始数）
					
					logger.debug("======!!!!!!!!!!!================> " + i);
					
					XSSFCell cell = row.getCell(i);
					/* if(cell==null) break; */  //拿到 cell 之后，不应当做 任何 操作、判断，要 原封原样 交给 indexer
					
					/** 如果有 "null 单元格"，则将他 补为 "blank 单元格" */
					if(cell == null) {
						cell = row.createCell(i);
						
						//System.out.println(cell.getCellType()); //CellType 为 blank
					}
					
					
					if(!started) {
						if(cellIndexer.triggerBeginning(cell)) {//开头
							logger.debug("开头啦~~~，将这个 cell 加入 list");
							
							cellList.add(cell);
							testIndexOverlapping(row, cellIndexSet, i);
							cellParser.setBeginIndex(i);/** 设置 beginIndex、endIndex 的 目的是为了在 gatherCellValues 派上用场*/
							cellParser.setEndIndex(i);
							
							started = true;
							
							cellIndexer.incrementIndex();
							continue;
							
						} else {//开不了头
							logger.debug("诶333，还是 开不了头");
							
							cellIndexer.incrementIndex();
							continue;
						}
					}
					
					if(!cellIndexer.triggerEnding(cell)) {//结不了尾，仍旧需要 将这个 cell 加入 list
						logger.debug("结不了尾，仍旧需要 将这个 cell 加入 list");
						
						cellList.add(cell);
						testIndexOverlapping(row, cellIndexSet, i);
						cellParser.setEndIndex(i);
						
						cellIndexer.incrementIndex();
						continue;
						
					}else {//结尾了，跳出 无限循环，不再 拿 cell 了
						logger.debug("结尾啦~~~~");
						started = false;
						
						break;
					}
				}
				
				XSSFCell[] cells = (XSSFCell[]) cellList.toArray(new XSSFCell[0]);
				logger.debug("收集的 列数：" + cells.length);
				
				//2、将 cells 交给  cellParser
				cellParser.setCells(cells);
				
				//3、解析 cellParser 中的  XSSFCell[] cells（提取值）
				cellParser.parse();
			}
			
			
			
			//如果 有 "行验证器" 或者 "使用了 hookList"，则要进行 gatherCellValues() 操作
			if((validators!=null && validators.length > 0) || (hookList!=null)) {
				Object[] cellValues = gatherCellValues(cellParsers);
				
				//行验证器
				if(validators.length > 0) {
					for (RowValidator rowValidator : validators) {
						rowValidator.validate(cellValues, row);
					}
				}
				
				//使用了 hookList
				if(hookList != null) {
					
					rowMapper.mapRow0(hookList, cellValues);
//					if(propertyNames!=null && clazz!=null) {
//						ele = clazz.newInstance();
//						
//						for (int i=0; i<propertyNames.length; i++) {
//							String propertyName = propertyNames[i];
//							Object cellValue = cellValues[i];
//							
//							/**
//							 * propertyName==null 是用来 空开位置 用的
//							 * cellValue!=null ：如果 值为 null 就 别 setProperty()，因为 javaBean 本身的值就是 null。而且 setProperty() 之后还会报错
//							 */
//							if((propertyName!=null) ) {
//		
//								//属性值装载
////								BeanUtils.setProperty(ele, propertyName, cellValue);
//								PropertyUtils.setProperty(ele, propertyName, cellValue);
//							}
//						}
//					}else {
//						
//						/**
//						 * 如果没有 定义 propertyNames，则认为：只取 Object[] cellValues 的 第一个元素
//						 */
//						ele = cellValues[0];
//					}
//					
//					eleList.add(ele);
				}
			}
			
			
			
			//TODO: 多个行 享用一组 CellParser，但是 CellIndexer 是不能 跨行的，要把 CellIndexer 的 恢复初始情况，即 reset
			//解决：方法1：深拷贝？  方法2：在 Indexer 中设计一个 reset 方法 
			
			//reset 之后，才能为 新的 行服务
			//注意：有时 cellParsers 的 indexer 会共享，也就是说 
			//多次 cellParser.getCellIndexer().resetIndex(); 可能 恢复的 是 同一个对象
			//不然会发生 无限循环
			for (CellParser cellParser : cellParsers) {
				cellParser.getCellIndexer().resetIndex();
				
				cellParser.setBeginIndex(-1);
				cellParser.setEndIndex(-1);
			}
			
		}
	}

	private void testIndexOverlapping(XSSFRow row, Set<Integer> cellIndexSet, int i) throws IndexOverlappingException {
		if(!cellIndexSet.add(i)) {
			/*
			 * 1) 同一 row   的 多个 cell，不应当出现 cellIndex 之间的 重叠
			 * 	对于一个 row 来说，有 2 个 CellParser 中 都同时包含了 (1行,3列) 这个单元格 的 cellValue，这其实是没有任何意义的
			 * 
			 * 2) 同一 sheet 的 多个  row，	可以出现  rowIndex 之间的 重叠
			 * 	1. 第一次 可以 解析 1-6 行（row）的 0-10 列；第二次 可以解析 1-6 行（row）的 11-20 列
			 * 	2. 可以对 1-6 行（row）的 0-10 列 进行反复的 解析
			 * 
			 */
			String msg = row.getSheet().getSheetName() + "页，"
						+ row.getRowNum() + "行"
						+ i + "列 的 单元格 被 重复提取了";
			
			throw new IndexOverlappingException(msg);
		}
	}
	
	public static void main(String[] args) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
//		Student ele = new Student();
//		logger.debug(ele);
//		BeanUtils.setProperty(ele, "id", 111);//正确
//		logger.debug(ele);
//		BeanUtils.setProperty(ele, "name", null);//正确
//		logger.debug(ele);
//		BeanUtils.setProperty(ele, "address", null);//正确
//		logger.debug(ele);
//		BeanUtils.setProperty(ele, "birthDay", null);//报错
//		logger.debug(ele);
		
		Student ele2 = new Student();
		logger.debug(ele2);
		PropertyUtils.setProperty(ele2, "id", 112);//正确
		logger.debug(ele2);
		PropertyUtils.setProperty(ele2, "name", null);//正确
		logger.debug(ele2);
		PropertyUtils.setProperty(ele2, "address", null);//正确
		logger.debug(ele2);
		PropertyUtils.setProperty(ele2, "birthDay", null);//报错
		logger.debug(ele2);
	}
	
	/**
	 * 收集 各个 CellParser 中的 cellValues，并 汇总到一个  Object[] 中
	 * 
	 * 将：
	 * [xxx][x]_[xx]_[xxx]__[x]___[xxxx] // "_" 为 cellParsers 未涉及到的 cell
	 * 汇总成：
	 * [xxxx_xx_xxx__x___xxxx] // "_" 为 null（补位用的）
	 * 
	 */
	private Object[] gatherCellValues(CellParser[] cellParsers0) {
		
		//TODO:由于使用了 函数式 的 indexer，所以 每行的 列数 可能不同，如果使用 rowMapper，就要非常小心了
		//TODO:建议在 RowMapper.mapRow() 中 判断参数 cellValues.length 的 长度，然后 在 判断 是否 要 
		//setProperties()、 hookList.add(ele);。这也是 RowMapper 的 意义所在
		//应当使用 rowValidator 进行检测，即 "hookList + rowSizeValidator 更配哦~"
		
		//0、剔除 "使用 indexer 进行扫描，但却没有 扫描到 任何 cell 的 CellParser"，
		//  即只抓取  cells.length>0  的 CellParser 进行分析
		List<CellParser> cellParserList = new ArrayList<CellParser>();
		
		for (CellParser cellParser : cellParsers0) {
			if(cellParser.getCells().length > 0)
				cellParserList.add(cellParser);
		}
		
		CellParser[] cellParsers = (CellParser[]) cellParserList.toArray(new CellParser[0]);
		
		if(cellParsers.length == 0) return new Object[0];
		
		//1、获取 最小、最大的 endIndex
		int minCellIndex = cellParsers[0].getBeginIndex(), //minCellIndex 是 整个 CellParser[] 的 偏移量
			maxCellIndex = cellParsers[0].getEndIndex();
		
		for (CellParser cellParser : cellParsers) {
			int beginIndex = cellParser.getBeginIndex();
			minCellIndex = minCellIndex > beginIndex ? beginIndex : minCellIndex;
			
			int endIndex = cellParser.getEndIndex();
			maxCellIndex = maxCellIndex < endIndex ? endIndex : maxCellIndex;
			
		}
		
		//2、构建空的 数组
		Object[] totalCellValues = new Object[maxCellIndex-minCellIndex+1];//用于 收集所有 cellParser 中包含的 cellValues
		
		//3、收集 各个 CellParser 中的 cellValues，并 汇集到 totalCellValues 中
		for (CellParser cellParser : cellParsers) {
			int beginIndex = cellParser.getBeginIndex();
			int endIndex = cellParser.getEndIndex();
			Object[] cellValues = cellParser.getCellValues();
			
			for(int i=beginIndex; i<endIndex+1; i++) {
				Object cellValue = cellValues[i-beginIndex];
				totalCellValues[i-minCellIndex] = cellValue;
			}
			
		}
		
		return totalCellValues;
	}
	
	
	public void printRow(XSSFRow row) {
		logger.debug(row.getFirstCellNum() + " ^^^ " + row.getLastCellNum());
		
		StringBuffer tmp = new StringBuffer("");
		//遍历 cell
		for (int i = 0; i < row.getLastCellNum(); i++) {
			tmp.append(row.getCell(i) + ", ");
		}
		logger.info(tmp);
	}
	
	
	/**
	 * 表头构造器：
	 * "验证表头中的每个字段" 是一个 经常会遇到的需求：
	 * 1) 使用 默认的 提取器：AdaptableCellExtractor
	 * 2) 只用 1 个验证器：验证表头的 字面值 是否正确
	 * 
	 * ==> 老的做法
	 * 	new CellParser[] {
			new CellParser(0, new CellValidator[]{new EquivalenceValidator("AAA")}),
			new CellParser(1, new CellValidator[]{new EquivalenceValidator("BBB")}),
			new CellParser(2, new CellValidator[]{new EquivalenceValidator("CCC")}),
			...
	 	}
	 *	
	 * ==> 新的做法
	 * constructHeaderParsers(String[] headers)
	 */
	public static CellParser[] constructHeaderParsers(String[] headers) {
		
		List<CellParser> headerParserList = new ArrayList<CellParser>();
		
		for (int i=0; i<headers.length; i++) {
			String header = headers[i];
			
			if(header == null) {//开发者 使用 null，来 告诉 constructHeaderParsers：跳过对 该列 表头的 检验
				continue;
			}
			
			headerParserList.add(
					new CellParser(i, new CellValidator[]{new EquivalenceValidator(header)})
			);
		}
		
		CellParser[] headerParsers = (CellParser[]) headerParserList.toArray(new CellParser[0]);
		
		return headerParsers;
	}
	
	

	public int getBeginIndex() {
		return beginIndex;
	}


	public void setBeginIndex(int beginIndex) {
		this.beginIndex = beginIndex;
	}


	public int getEndIndex() {
		return endIndex;
	}


	public void setEndIndex(int endIndex) {
		this.endIndex = endIndex;
	}

	
	public RowIndexer getRowIndexer() {
		return rowIndexer;
	}

	public void setRowIndexer(RowIndexer rowIndexer) {
		this.rowIndexer = rowIndexer;
	}
	

	public XSSFRow[] getRows() {
		return rows;
	}


	public void setRows(XSSFRow[] rows) {
		this.rows = rows;
	}


	public CellParser[] getCellParsers() {
		return cellParsers;
	}


	public void setCellParsers(CellParser[] cellParsers) {
		this.cellParsers = cellParsers;
	}


	public RowValidator[] getValidators() {
		return validators;
	}


	public void setValidators(RowValidator[] validators) {
		this.validators = validators;
	}

	public List<?> getHookList() {
		return hookList;
	}

	public void setHookList(List<?> hookList) {
		this.hookList = hookList;
	}

	public RowMapper<?> getRowMapper() {
		return rowMapper;
	}

	public void setRowMapper(RowMapper<?> rowMapper) {
		this.rowMapper = rowMapper;
	}
	
	
}
